
// Copyright (c) 2024 刻BITTER
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.


#pragma once


#include <cstdint>


namespace scheduler_basic {

#ifdef ARDUINO

    #include "Arduino.h"

    class ArduinoUsSource {
       public:
        using TimeType = uint32_t;

       private:
        TimeType _last_time = 0;

       public:
        ArduinoUsSource() {
            reset();
        }

        TimeType now() {
            return micros();
        }

        TimeType diff() {
            return now() - _last_time;
        }

        void reset() {
            _last_time = now();
        }
    };


    class ArduinoMsSource {
       public:
        using TimeType = uint32_t;

       private:
        TimeType _last_time = 0;

       public:
        ArduinoMsSource() {
            reset();
        }

        TimeType now() {
            return millis();
        }

        TimeType diff() {
            return now() - _last_time;
        }

        void reset() {
            _last_time = now();
        }
    };
#endif


#ifdef USE_HAL_DRIVER

    extern uint32_t HAL_GetTick();
    extern uint32_t SystemCoreClock;

    // TODO:
#endif


#if __has_include("windows.h")

    #include <windows.h>

    /**
     * @brief 使用Win32 API 获取时间
     * 
     * 依赖winmm.lib，可以将下面的代码加入任意源文件，否则会有链接错误：
     * #pragma comment(lib, "winmm.lib")
     * 
     */
    class MsMsSource {
       public:
        using TimeType = DWORD;

       private:
        TimeType _last_time = 0;

       public:
        MsMsSource() {
            reset();
        }

        TimeType now() {
            return timeGetTime();
        }

        TimeType diff() {
            return now() - _last_time;
        }

        void reset() {
            _last_time = now();
        }
    };

#endif


#if __has_include("chrono") && 0

    #error "由于神秘的原因，chrono 头文件似乎不可用"

    #include <chrono>

    class ChronoMsSource {
       public:
        using TimeType = std::chrono::milliseconds::rep;

       private:
        TimeType _last_time = 0;

       public:
        ChronoMsSource() {
            reset();
        }

        TimeType now() {
            using namespace std::chrono;
            auto t = system_clock::now();
            auto tt = t.time_since_epoch();
            auto ms = duration_cast<milliseconds>(tt).count();
            return ms;
        }

        TimeType diff() {
            return now() - _last_time;
        }

        void reset() {
            _last_time = now();
        }
    };

#endif

}  // namespace scheduler_basic
